home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / piemnsrc.sit / Pie PopupWindow.c < prev    next >
Text File  |  1989-09-14  |  11KB  |  375 lines

  1. /*
  2.  * Pie PopupWindow.c -    Contains the function DrawPieMenu which is callable from
  3.  *                        HyperCard via an XCMD interface.
  4.  */
  5.  
  6. #include    <MacTypes.h>
  7. #include    <QuickDraw.h>
  8. #include    "HyperXCmd.h"
  9. #include    "circledata.h"        /* definitions of the circles used for plotting */
  10.  
  11.  
  12. #define    MENU_SEPARATOR        ';'        /* character separating menu string items */
  13. #define    ONE_HALF_POPUP_X    140        /* 1/2 the width of the popup menu */
  14. #define    ONE_HALF_POPUP_Y    70        /* 1/2 the height of the popup menu */
  15. #define    BORDER_SIZE            4        /* minimum # of pixels to have around popup */
  16. #define    MENUBAR_HEIGHT        20        /* # of pixels in Mac's menu bar */
  17.  
  18.  
  19.  
  20. /* Local Function Prototypes */
  21. int        DrawPieMenu(Point, char *, int, int, int, int);
  22. char    *strcpy(char *dest, char *src);
  23. int        strlen(char *str);
  24.  
  25.  
  26.  
  27. /* Number of different pie wedge patterns */
  28. #define    NUM_PIE_PATTERNS    14
  29.  
  30. /* The actual patterns used for the pie wedges */
  31. long    pattern[NUM_PIE_PATTERNS][2] =
  32. {
  33.             0x77DD77DD, 0x77DD77DD,
  34.             0x88228822, 0x88228822,
  35.             0xAA55AA55, 0xAA55AA55,
  36.             0xDBB6DBB6, 0xDBB6DBB6,
  37.             0x93499349, 0x93499349,
  38.             0xCC33CC33, 0xCC33CC33,
  39.             0xAAAAAAAA, 0xAAAAAAAA,
  40.             0xC00CC00C, 0xC00CC00C,
  41.             0xF0F0F0F0, 0xF0F0F0F0,
  42.             0xCC00CC00, 0xCC00CC00,
  43.             0x18181818, 0x18181818,
  44.             0xF00FF00F, 0xF00FF00F,
  45.             0x80048004, 0x80048004,
  46.             0xC0C00C0C, 0xC0C00C0C
  47. };
  48.  
  49. /*
  50.  * We need to have our own black pattern because the normal pen pattern
  51.  * of black is referenced off A5 as part of the QuickDraw globals and since
  52.  * this is a code resource we've built this referencing globals off A4.
  53.  */
  54. long    black_pattern[2] = { 0xFFFFFFFF, 0xFFFFFFFF };
  55.  
  56.  
  57. /* Maximum number of pie wedges allowed */
  58. #define    MAX_MENU_ITEMS    40
  59.  
  60. /* Rectangles used to hold the coordinates of the label's rectangles */
  61. struct    {
  62.     Rect    r;
  63. } label_rects[MAX_MENU_ITEMS];
  64.  
  65.  
  66. /* Region table used to hold the region handles for the pie wedges */
  67. RgnHandle    pie_rgns[MAX_MENU_ITEMS];
  68.  
  69. /* The region for the center "non-hot" region is treated separately */
  70. RgnHandle    center_rgn;
  71.  
  72.  
  73.  
  74.  
  75. /*
  76.  * Function:    DrawPieMenu(windowLoc,menuList,num_menu_items,font,font_size)
  77.  *
  78.  * Inputs:        Point windowLoc -        Location to center the popup about.
  79.  *                char  *menuList -        String containing comma separated menu items.
  80.  *                int   num_menu_items -    Number of menu items in the menuList.
  81.  *                int      default_item -    Default to highlight, 0 if no default.
  82.  *                int   font -            Number of font to use.
  83.  *                int      font_size -        Size of font in pixels.
  84.  *
  85.  * Outputs:        Displays a pie menu to the user for selection.
  86.  *
  87.  * Returns:        The number of the selected menu item or zero if none.
  88.  *
  89.  */
  90. int
  91. DrawPieMenu(windowLoc,menuList,num_menu_items,default_item,font,font_size)
  92.     Point    windowLoc;
  93.     char     *menuList;
  94.     int        num_menu_items;
  95.     int        default_item;
  96.     int        font;
  97.     int        font_size;
  98. {
  99.     Rect            popupRect;            /* rectangle of the pie popup menu */
  100.     Point            mouseLoc;            /* current location of the mouse */
  101.     Point            start_pt;            /* start point for label placement */
  102.     Point            end_pt;                /* end point for label placement */
  103.     WindowRecord     window_rec;            /* static area for pie popup window */
  104.     WindowPtr        origWindow;            /* save area for original grafport */
  105.     WindowPtr        pieWindow;            /* pointer to pie popup window */
  106.     char            label_buf[80];        /* temp scratch buffer for label generation*/
  107.     char            *cp;                /* temp work pointer */
  108.     short            label_width;        /* width of label in pixels */
  109.     int                label_len;            /* number of characters in a label */
  110.     int                i,j,k;                /* temporary index variables */
  111.     int                old_rgn;            /* index of previously selected region */
  112.     int                in_a_region;        /* TRUE iff cursor is in a pie region */
  113.     int                line_start;            /* index of points on inner/outer circles */
  114.     int                line_end;            /*   used to connect a label to the wedge */
  115.     int                scrn_left;            /* coordinate of left side of the screen */
  116.     int                scrn_right;            /* coordinate of right side of the screen */
  117.     int                scrn_top;            /* coordinate of top of the screen */
  118.     int                scrn_bottom;        /* coordinate of bottom of the screen */
  119.     int                rgn_i_pts;            /* number of points in region of inner circle */
  120.     int                extra_i_pts;        /* extra inner circle points to distribute */
  121.     int                next_i_pt;            /* index of next inner circle point to use */
  122.     int                points_this_i_rgn;    /* number inner points to use for current region */
  123.     int                rgn_o_pts;            /* number of points in region of outer circle */
  124.     int                extra_o_pts;        /* extra outer circle points to distribute */
  125.     int                next_o_pt;            /* index of next outer circle point to use */
  126.     int                points_this_o_rgn;    /* number outer points to use for current region */
  127.  
  128.  
  129.     /* Before we do any work, validate that the mouse is still depressed */
  130.     if (! StillDown())
  131.         return (0);
  132.     
  133.     
  134.     /* Save the grafport of the current window */
  135.     GetPort(&origWindow);
  136.     
  137.     
  138.     /* Obtain the dimensions of the screen we are running on */
  139.     scrn_left   = origWindow->portBits.bounds.left;
  140.     scrn_right  = origWindow->portBits.bounds.right;
  141.     scrn_top    = origWindow->portBits.bounds.top;
  142.     scrn_bottom = origWindow->portBits.bounds.bottom;
  143.     
  144.     
  145.     /* Obtain the current location of the mouse to center the popup about */
  146.     GetMouse(&mouseLoc);
  147.     mouseLoc.h += windowLoc.h;
  148.     mouseLoc.v += windowLoc.v;
  149.     
  150.     
  151.     /* Make sure the pie popup will fit on the screen, adjust if necessary */
  152.     if ( mouseLoc.h <= (scrn_left + ONE_HALF_POPUP_X) )
  153.         mouseLoc.h = scrn_left + ONE_HALF_POPUP_X + BORDER_SIZE;
  154.         
  155.     if ( (mouseLoc.h + ONE_HALF_POPUP_X) >= scrn_right )
  156.         mouseLoc.h = scrn_right - (ONE_HALF_POPUP_X + BORDER_SIZE);
  157.         
  158.     if ( mouseLoc.v <= (scrn_top + ONE_HALF_POPUP_Y + MENUBAR_HEIGHT) )
  159.         mouseLoc.v = scrn_top + ONE_HALF_POPUP_Y + MENUBAR_HEIGHT + BORDER_SIZE;
  160.         
  161.     if ( (mouseLoc.v + ONE_HALF_POPUP_Y) >= scrn_bottom )
  162.         mouseLoc.v = scrn_bottom - (ONE_HALF_POPUP_Y + BORDER_SIZE);
  163.  
  164.         
  165.     
  166.     /* Create a rectangle for the popup using the adjusted coordinates */
  167.     SetRect(&popupRect, mouseLoc.h - ONE_HALF_POPUP_X, mouseLoc.v - ONE_HALF_POPUP_Y,
  168.                         mouseLoc.h + ONE_HALF_POPUP_X, mouseLoc.v + ONE_HALF_POPUP_Y);
  169.     
  170.     
  171.     /* Open a dialog box window to place the pie menu within, and make it current */                
  172.     pieWindow = NewWindow(&window_rec,&popupRect,"\pPie Popup",true, altDBoxProc,-1L,true,0);
  173.     SetPort(pieWindow);
  174.  
  175.     /* The region points headers assume a 0,0 based coordinate system */
  176.     SetOrigin(-(ONE_HALF_POPUP_X),-(ONE_HALF_POPUP_Y));
  177.  
  178.     
  179.     /* Create the center "non-hot" region in the pie menu. */
  180.     center_rgn = NewRgn();
  181.     PenSize(1,1);
  182.     MoveTo(c_circle_points[0].x,c_circle_points[0].y);
  183.     OpenRgn();
  184.     for (i = 1; i < NUM_C_POINTS; i++) {
  185.         LineTo(c_circle_points[i].x,c_circle_points[i].y);
  186.     }    
  187.     CloseRgn(center_rgn);
  188.     PenPat(black_pattern);
  189.     FrameRgn(center_rgn);
  190.     
  191.     
  192.     /* Dissallow more menu items than we have regions to display */
  193.     if (num_menu_items > MAX_MENU_ITEMS)
  194.         num_menu_items = MAX_MENU_ITEMS;
  195.         
  196.         
  197.     /* Create as many regions as their are pie slices required */
  198.     for (i = 0; i < num_menu_items; i++)
  199.         pie_rgns[i] = NewRgn();
  200.     
  201.     
  202.     /* Calculate the number of points to use in defining a region */
  203.     rgn_i_pts = NUM_I_POINTS / num_menu_items;
  204.     extra_i_pts = NUM_I_POINTS % num_menu_items;
  205.     rgn_o_pts = NUM_O_POINTS / num_menu_items;
  206.     extra_o_pts = NUM_O_POINTS % num_menu_items;
  207.  
  208.  
  209.     /* Initialize next points and next menu selection to use */
  210.     next_i_pt = 0;
  211.     next_o_pt = 0;
  212.     cp = menuList;
  213.     
  214.     /* Plot the regions */
  215.     for (i = 0; i < num_menu_items; i++) {
  216.         points_this_i_rgn = rgn_i_pts;
  217.         if (extra_i_pts) {
  218.             ++points_this_i_rgn;
  219.             --extra_i_pts;
  220.         }
  221.         
  222.         points_this_o_rgn = rgn_o_pts;
  223.         if (extra_o_pts) {
  224.             ++points_this_o_rgn;
  225.             --extra_o_pts;
  226.         }
  227.         
  228.         /* Draw a line from the center of this arc to the outer circle */
  229.         line_start = (points_this_i_rgn / 2) + next_i_pt;
  230.         line_end   = (points_this_o_rgn / 2) + next_o_pt;
  231.         PenSize(2,2);
  232.         MoveTo(i_circle_points[line_start].x,i_circle_points[line_start].y);
  233.         LineTo(o_circle_points[line_end].x,o_circle_points[line_end].y);
  234.         
  235.         /* Put a horizontal tab 6 pixels long on the radiating line */
  236.         if ( i < (num_menu_items / 2) )
  237.             LineTo(o_circle_points[line_end].x + 6, o_circle_points[line_end].y);
  238.         else
  239.             LineTo(o_circle_points[line_end].x - 6, o_circle_points[line_end].y);
  240.         next_o_pt += points_this_o_rgn;
  241.         
  242.         /* Set the typeface and style for the text. */
  243.         TextFont(font);
  244.         TextFace(0);
  245.         TextSize(font_size);
  246.                 
  247.         /* Isolate the next label from the MenuList and display it. */
  248.         j = 0;
  249.  
  250.         while ( (*cp != MENU_SEPARATOR) && (*cp != '\0') )
  251.             label_buf[j++] = *cp++;
  252.  
  253.         label_buf[j] = '\0';
  254.         ++cp;            
  255.  
  256.         /* Calculate the number of pixels contained in this label. */
  257.         label_len = strlen(label_buf);
  258.         label_width = TextWidth(label_buf,0,label_len);
  259.         
  260.         
  261.         /* Calculate where the start point of the label should be located. */
  262.         if ( i < (num_menu_items / 2) ) {
  263.             SetPt(&start_pt,
  264.                   o_circle_points[line_end].x + 10,
  265.                   o_circle_points[line_end].y + 4);
  266.         }
  267.         else {
  268.             SetPt(&start_pt,
  269.                   o_circle_points[line_end].x - (8 + label_width),
  270.                   o_circle_points[line_end].y + 4);
  271.         }
  272.  
  273.         /* The end point is to the left of the start by the length of the label. */
  274.         SetPt(&end_pt, (start_pt.h + label_width), start_pt.v);
  275.         
  276.         MoveTo(start_pt.h,start_pt.v);    
  277.         DrawText(label_buf,0,label_len);
  278.  
  279.         /* Calculate the rectangle that encloses the label */        
  280.         SetRect(&label_rects[i], start_pt.h - 2, start_pt.v - font_size, 
  281.                                  end_pt.h + 2, end_pt.v + 2);
  282.                 
  283.                 
  284.         /* Open the next region, assign points, close it, fill it, remove center. */
  285.         MoveTo(0,0);
  286.         PenSize(1,1);
  287.         OpenRgn();
  288.         for (j = points_this_i_rgn; j != 0; j--, next_i_pt++)
  289.             LineTo(i_circle_points[next_i_pt].x,i_circle_points[next_i_pt].y);    
  290.         LineTo(0,0);
  291.         CloseRgn(pie_rgns[i]);
  292.         DiffRgn(pie_rgns[i],center_rgn,pie_rgns[i]);
  293.         FillRgn(pie_rgns[i],pattern[i]);
  294.     }
  295.  
  296.  
  297.     /* 
  298.      * All of the work displaying the pie popup menu is now complete.
  299.      * Track the mouse while the button is still down and highlight /
  300.      * dehilight the appropriate selections as the user moves the mouse.
  301.      */
  302.     old_rgn = -1;                /* Indicate that we aren't in any region */
  303.  
  304.     while (Button()) {
  305.         SystemTask();
  306.         in_a_region = FALSE;
  307.         GetMouse(&mouseLoc);
  308.         for (i = 0; i < num_menu_items; i++) {
  309.             if (PtInRgn(mouseLoc,pie_rgns[i]) ) {
  310.                 in_a_region = TRUE;
  311.                 if (old_rgn == i) 
  312.                     break;
  313.                 else {
  314.                     in_a_region = TRUE;
  315.                     PenPat(black_pattern);
  316.                     PaintRgn(pie_rgns[i]);
  317.                     InvertRect(&label_rects[i]);
  318.                     if (old_rgn != -1) {
  319.                         FillRgn(pie_rgns[old_rgn],pattern[old_rgn]);
  320.                         InvertRect(&label_rects[old_rgn]);
  321.                     }
  322.                     old_rgn = i;
  323.                 }
  324.             }
  325.         }
  326.         
  327.         /* Deselect the previously selected region when we exit the pie regions */
  328.         if ( (in_a_region == FALSE) && (old_rgn != -1) ) {
  329.             FillRgn(pie_rgns[old_rgn],pattern[old_rgn]);
  330.             InvertRect(&label_rects[old_rgn]);
  331.             old_rgn = -1;
  332.         }
  333.     }
  334.  
  335.     /* Discard events that have occurred during user's selection */
  336.     FlushEvents(everyEvent, 0);
  337.  
  338.     /* Dispose of the previously created pie regions */
  339.     for (i = 0; i < num_menu_items; i++)
  340.         DisposeRgn(pie_rgns[i]);
  341.         
  342.     /* Dispose of the center 'non-hot' region */
  343.     DisposeRgn(center_rgn);
  344.     
  345.     /* Switch back to the original grafport and kill the pie window */
  346.     SetPort(origWindow);
  347.     CloseWindow(pieWindow);
  348.  
  349.     /* Tell the caller what menu item was selected */
  350.     return ( (old_rgn == -1) ? 0 : ++old_rgn);
  351. }
  352.  
  353.  
  354. char *
  355. strcpy(s,t)
  356.     register char *s, *t;
  357. {
  358.     char *dest = s;
  359.     
  360.     while (*s++ = *t++);
  361.     return (dest);
  362. }
  363.  
  364.  
  365. int
  366. strlen(s)
  367.     register char *s;
  368. {
  369.     char *p = s;
  370.     
  371.     while (*p != '\0')
  372.         p++;
  373.     return(p-s);
  374. }
  375.